package ch.hslu.gl20vscpudemo;

import java.lang.Math;

public class GaussKernel {
	
	/**
	 * calculate an gaussian matrix
	 * @param kernel values are stored in kernel
	 * @param sigma gaussian sigma
	 * @param normTo to normalize kernel
	 */
	public static void calcMatrix(double[][] kernel, double sigma, double normTo){
		double yMean = (kernel.length-1.0)/2.0;
		double xMean = (kernel[0].length-1.0)/2.0;

		/* calculate kernel and normalize to one */
		for(int y=0; y<kernel.length; ++y){
			for(int x=0; x<kernel[0].length; ++x){
				kernel[y][x] = gaussian((double)x-xMean,(double)y-yMean, sigma);
			}
		}
		normalize(kernel, normTo);
	}

	/**
	 * calculate an gaussian matrix
	 * @param kernel values are stored in kernel
	 * @param sigma gaussian sigma
	 * @param normTo to normalize kernel
	 */
	public static void calcMatrix(float[][] kernel, double sigma, float normTo){
		double[][] dKernel = new double[kernel.length][kernel[0].length];
		calcMatrix(dKernel, (double)sigma, (double)normTo);
		for(int y=0; y<kernel.length; y++){
			for(int x=0; x<kernel[0].length; x++){
				kernel[y][x] = (float)dKernel[y][x];
			}
		}
	}

	/**
	 * calculate an gaussian matrix
	 * @param kernel values are stored in kernel
	 * @param sigma gaussian sigma
	 * @param normTo to normalize kernel
	 */
	public static void calcMatrix(int[][] kernel, double sigma, int normTo){
		double[][] dKernel = new double[kernel.length][kernel[0].length];
		calcMatrix(dKernel, (double)sigma, (double)normTo);
		for(int y=0; y<kernel.length; y++){
			for(int x=0; x<kernel[0].length; x++){
				kernel[y][x] = (int)dKernel[y][x];
			}
		}
	}
	
	/* gaussian: same alogrithm as http://www.mathworks.ch/ch/help/images/ref/fspecial.html */
	private static double gaussian(double x, double y, double sigma)	{
		return Math.exp(-(Math.pow(x,2.0)+Math.pow(y,2.0))/(2.0*Math.pow(sigma,2.0)));
	}

	/* normalize values */
	private static void normalize(double values[][], double target){
		int x,y;
		double sum;
		sum=0.0;
		for(y=0; y<values.length; y++){
			for(x=0;x<values[0].length;x++){
				sum += values[y][x];
			}
		}
		for(y=0; y<values.length; y++){
			for(x=0; x<values[0].length; x++){
				values[y][x] /= sum;
				values[y][x] *= target;
			}
		}
	}
}
